package com.esunny.resourcevisualization.service.impl;

import com.esunny.resourcevisualization.constant.EntityUsingStatus;
import com.esunny.resourcevisualization.constant.ResourceFileType;
import com.esunny.resourcevisualization.domain.entity.*;
import com.esunny.resourcevisualization.domain.response.ReturnStructure;
import com.esunny.resourcevisualization.manage.ResourceTypeFieldManage;
import com.esunny.resourcevisualization.manage.ResourceTypeManage;
import com.esunny.resourcevisualization.manage.UserManage;
import com.esunny.resourcevisualization.service.ExcelOperationService;
import com.esunny.resourcevisualization.service.ResourceTypeEntityDataService;
import com.esunny.resourcevisualization.service.ResourceTypeEntityService;
import com.esunny.resourcevisualization.service.UserEntityService;
import com.esunny.resourcevisualization.util.ExcelUtil;
import com.esunny.resourcevisualization.util.FileUtil;
import com.esunny.resourcevisualization.util.UUIDUtil;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @version 1.0.0.0
 * @ClassName ExcelOperationServiceImpl
 * @Description excel文件操作
 * @Author baochencong
 * @Date 2020/11/2 14:14
 */
@Service
public class ExcelOperationServiceImpl implements ExcelOperationService {

    @Value("${resourcevisualization.path.upload}")
    private String tempPath;

    @Resource
    private HttpServletResponse response;

    @Resource
    private ResourceTypeFieldManage resourceTypeFieldManage;

    @Resource
    private UserManage userManage;

    @Resource
    private UserEntityService userEntityService;

    @Resource
    private ResourceTypeManage resourceTypeManage;

    @Resource
    private ResourceTypeEntityService resourceTypeEntityService;

    @Resource
    private ResourceTypeEntityDataService resourceTypeEntityDataService;

    @Override
    public ReturnStructure downloadTemplate(String name) {
        // 判断该资源类别是否存在
        if (resourceTypeManage.getResourceTypeByName(name) == null) {
            return ReturnStructure.NOT_FOUND("该资源类别不存在", null);
        }
        String title = resourceTypeManage.getResourceTypeByName(name).getResourceTypeTitle();

        // 构建excel模板内容
        List<ExcelSheetVO> sheetList = buildWorkBookTemplate(name);

        // 获取excel工作薄
        XSSFWorkbook workbook = new ExcelUtil().CreateExcelXLSX(sheetList, name);

        // 将工作薄数据写入响应头
        try {
            OutputStream os = response.getOutputStream();
            workbook.write(os);
            response.setContentType("application/force-download");
            String fileName = new String((title + "." + ResourceFileType.RESOURCE_TYPE_XLSX).getBytes("GBK"), StandardCharsets.ISO_8859_1);
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
        } catch (IOException e) {
            return ReturnStructure.ERROR("下载模板失败", null);
        }

        return ReturnStructure.SUCCESS("下载模板成功", null);
    }

    @Override
    public ReturnStructure importResourceData(MultipartFile file) {
        File excelFile = new File(tempPath + File.separator + UUIDUtil.generateUUID() + "." + ResourceFileType.RESOURCE_TYPE_XLSX);

        List<ExcelSheetVO> sheetList = getSheetList(file, excelFile);
        if (sheetList == null) {
            return ReturnStructure.ERROR("读取EXCEL内容失败", null);
        }

        ReturnStructure returnStructure = insertResourceData(sheetList.get(0));
        FileUtil.delFile(excelFile);

        return returnStructure;
    }

    @Override
    public ReturnStructure downloadResourceData(String name) {
        // 判断该资源类别是否存在
        if (resourceTypeManage.getResourceTypeByName(name) == null) {
            return ReturnStructure.NOT_FOUND("该资源类别不存在", null);
        }

        XSSFWorkbook workBook = getWorkBook(name, resourceTypeEntityService.getResourceTypeEntityListByName(name));

        return setWorkBookToResponse(workBook, name);
    }

    @Override
    public ReturnStructure downloadSelectedResourceData(List<ResourceTypeEntity> entityList) {
        String name = entityList.get(0).getResourceTypeName();
        formatEntityStatusNameToTitle(entityList);
        XSSFWorkbook workBook = getWorkBook(name, entityList);

        return setWorkBookToResponse(workBook, name);
    }

    /**
     * 将工作薄流写入响应头的输出流
     *
     * @param workbook 工作薄
     * @param name     资源类别英文名
     * @return 写入结果
     */
    private ReturnStructure setWorkBookToResponse(XSSFWorkbook workbook, String name) {
        // 将工作薄数据写入响应头
        try {
            String fileName = new String((resourceTypeManage.getResourceTypeByName(name).getResourceTypeTitle() + "." + ResourceFileType.RESOURCE_TYPE_XLSX).getBytes("GBK"), StandardCharsets.ISO_8859_1);
            response.setHeader("Content-Type", "application/x-download");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            OutputStream os = response.getOutputStream();
            workbook.write(os);
        } catch (IOException e) {
            return ReturnStructure.ERROR("下载数据失败", null);
        }

        return ReturnStructure.SUCCESS("下载数据成功", null);
    }

    /**
     * 获取工作薄流
     *
     * @param name       资源类别英文名
     * @param entityList 要下载的实体列表
     * @return 工作薄流
     */
    private XSSFWorkbook getWorkBook(String name, List<ResourceTypeEntity> entityList) {
        List<ExcelSheetVO> sheetList = buildWorkBookTemplate(name);

        setSheetData(sheetList.get(0), name, entityList);

        // 获取excel工作薄
        return new ExcelUtil().CreateExcelXLSX(sheetList, name);
    }

    /**
     * 添加工作表数据
     *
     * @param sheet      工作表
     * @param name       资源类别英文名
     * @param entityList 需要加入的资源实体的
     */
    private void setSheetData(ExcelSheetVO sheet, String name, List<ResourceTypeEntity> entityList) {
        sheet.setSheetName(name);
        List<List<Object>> sheetDataList = sheet.getSheetDataList();

        if (entityList.size() <= 0) {
            return;
        }
        List<ResourceTypeField> fieldList = resourceTypeFieldManage.getResourceTypeFieldByName(name);

        for (ResourceTypeEntity entity : entityList) {
            List<Object> singleRowData = new ArrayList<>();

            singleRowData.add(entity.getResourceTypeEntityId());

            for (ResourceTypeField fieldInfo : fieldList) {
                ResourceTypeEntityData entityData = resourceTypeEntityDataService.getResourceTypeEntityDataByEntityIdAndFieldName(entity.getResourceTypeEntityId(), fieldInfo.getResourceTypeFieldName());
                if (entityData != null) {
                    singleRowData.add(entityData.getResourceTypeEntityDataValue());
                } else {
                    singleRowData.add("");
                }
            }
            singleRowData.add(entity.getResourceTypeEntityDescription());
            singleRowData.add(entity.getStatus());
            singleRowData.add(entity.isMayApply()?"是":"否");
            UserEntity userEntityByEntityId = userEntityService.getUserEntityByEntityId(entity.getResourceTypeEntityId());
            if (userEntityByEntityId != null) {
                singleRowData.add(userEntityByEntityId.getUsername());
            }

            sheetDataList.add(singleRowData);
        }
    }

    /**
     * 向数据库插入excel数据
     *
     * @param sheet sheet信息
     * @return 插入结果
     */
    private ReturnStructure insertResourceData(ExcelSheetVO sheet) {
        String name = sheet.getSheetName();

        List<ResourceTypeField> fieldList = resourceTypeFieldManage.getResourceTypeFieldByName(name);
        int fieldCount = fieldList.size();

        List<List<Object>> sheetDataList = sheet.getSheetDataList();
        List<Object> singleRowData;
        for (int rowIndex = 1; rowIndex < sheetDataList.size(); rowIndex++) {
            singleRowData = sheetDataList.get(rowIndex);

            String resourceTypeDescription = singleRowData.get(fieldCount + 1) == null ? "" : String.valueOf(singleRowData.get(fieldCount + 1));
            String status = singleRowData.get(fieldCount + 2) == null ? "" : String.valueOf(singleRowData.get(fieldCount + 2));
            boolean mayApply = singleRowData.get(fieldCount + 3) != null && singleRowData.get(fieldCount + 3).equals("是");
            //添加实体
            ResourceTypeEntity entity = new ResourceTypeEntity(name, resourceTypeDescription, status);
            entity.setMayApply(mayApply);
            if (singleRowData.get(0) == null || singleRowData.get(0).equals("")) {
                resourceTypeEntityService.addResourceTypeEntity(entity);
            } else {
                entity.setResourceTypeEntityId(Integer.parseInt(String.valueOf(singleRowData.get(0))));
                resourceTypeEntityService.updateResourceTypeEntityByEntityId(entity);
            }

            //添加实体动态字段值
            for (int columnIndex = 1; columnIndex <= fieldCount; columnIndex++) {
                Object column = singleRowData.get(columnIndex);
                ResourceTypeEntityData entityData = new ResourceTypeEntityData(entity.getResourceTypeEntityId(), name, fieldList.get(columnIndex - 1).getResourceTypeFieldName(), column == null ? "" : String.valueOf(column));
                resourceTypeEntityDataService.updateResourceTypeEntityDataByEntityIdAndFieldName(entityData);
            }

            // 添加使用人
            Object userMan = singleRowData.get(fieldCount + 4);
            if (userMan != null) {
                User user = userManage.getUserByRealName(String.valueOf(userMan).trim());
                if (user != null) {
                    UserEntity userEntity = new UserEntity();
                    userEntity.setUsername(user.getUsername());
                    userEntity.setEntityId(entity.getResourceTypeEntityId());
                    userEntity.setUserGroupName(user.getUserGroupName());
                    if (userEntityService.getUserEntityByEntityId(entity.getResourceTypeEntityId()) == null) {
                        userEntityService.addUserEntity(userEntity);
                    } else {
                        userEntityService.updateUserEntityByEntityId(userEntity);
                    }
                }
            }

        }

        return ReturnStructure.SUCCESS("导入成功", null);
    }

    /**
     * 获取sheet列表
     *
     * @param file excel文件
     * @return sheet列表
     */
    private List<ExcelSheetVO> getSheetList(MultipartFile file, File excelFile) {
        List<ExcelSheetVO> sheetList;
        try {
            file.transferTo(excelFile);
            ExcelUtil excelUtil = new ExcelUtil();
            sheetList = excelUtil.ReadExcel(excelFile, file.getOriginalFilename(), null, null);
        } catch (IOException e) {
            return null;
        }
        return sheetList;
    }

    /**
     * 构建工作薄模板
     *
     * @param name 资源类别英文名
     * @return 构建好的模板数据
     */
    @NotNull
    private List<ExcelSheetVO> buildWorkBookTemplate(String name) {
        List<ResourceTypeField> resourceTypeFieldListByName = resourceTypeFieldManage.getResourceTypeFieldByName(name);

        // 创建一个sheet并命名
        List<ExcelSheetVO> sheetList = new ArrayList<>();
        ExcelSheetVO sheet = new ExcelSheetVO();
        sheetList.add(0, sheet);
        sheet.setSheetName(name);

        // 设置单个sheet数据
        List<List<Object>> sheetDataList = new ArrayList<>();
        sheet.setSheetDataList(sheetDataList);

        // 设置单个sheet列头信息
        List<Object> cellNameList = new ArrayList<>();
        cellNameList.add("实体id");
        if (resourceTypeFieldListByName.size() > 0) {
            for (ResourceTypeField fieldItem : resourceTypeFieldListByName) {
                cellNameList.add(fieldItem.getResourceTypeFieldTitle());
            }
        }
        cellNameList.add("描述");
        cellNameList.add("状态");
        cellNameList.add("是否可申请");
        cellNameList.add("使用人");

        // 将列头信息加入sheet
        sheetDataList.add(cellNameList);

        return sheetList;
    }

    /**
     * 格式化资源实体状态
     *
     * @param resourceTypeEntityList 资源实体列表信息
     */
    private void formatEntityStatusNameToTitle(@NotNull List<ResourceTypeEntity> resourceTypeEntityList) {
        for (ResourceTypeEntity eachEntity : resourceTypeEntityList) {
            for (int statusIndex = 0; statusIndex < EntityUsingStatus.usingStatusNameList.length; statusIndex++) {
                if (eachEntity.getStatus().equals(EntityUsingStatus.usingStatusNameList[statusIndex])) {
                    eachEntity.setStatus(EntityUsingStatus.usingStatusTitleList[statusIndex]);
                }
            }
        }
    }

}
